package com.diy.sigmund.diycommon.spring.extensionpoint;

import com.diy.sigmund.diycommon.entity.constant.LogConstant;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * 通过注册一个关闭钩子来停止某个服务
 *
 * 注册一个新的虚拟机关闭挂钩。
 * Java 虚拟机关闭以响应两种事件：
 * 程序正常退出，当最后一个非守护线程退出或调用exit （等效于System.exit ）方法时，或
 * 虚拟机响应用户中断（例如键入^C ）或系统范围的事件（例如用户注销或系统关闭）而终止。
 * 关闭挂钩只是一个已初始化但未启动的线程。当虚拟机开始其关闭序列时，它将以某种未指定的顺序启动所有已注册的关闭挂钩并让它们同时运行。当所有钩子都完成后，如果 finalization-on-exit 已启用，它将运行所有未调用的终结器。最后，虚拟机将停止。请注意，在关闭序列期间，守护线程将继续运行，如果通过调用exit方法启动关闭，非守护线程也将继续运行。
 * 一旦关闭序列开始，它只能通过调用halt方法来停止，该方法会强制终止虚拟机。
 * 一旦关闭序列开始，就不可能注册新的关闭挂钩或取消注册先前注册的挂钩。尝试这些操作中的任何一个都将导致IllegalStateException 。
 * 关闭挂钩在虚拟机生命周期的一个微妙时刻运行，因此应该进行防御性编码。特别是，它们应该写成线程安全的，并尽可能避免死锁。他们也不应该盲目依赖可能已经注册了自己的关闭钩子的服务，因此他们自己可能正在关闭的过程中。例如，尝试使用其他基于线程的服务（例如 AWT 事件调度线程）可能会导致死锁。
 * 关闭挂钩也应该快速完成它们的工作。当程序调用exit时，期望虚拟机将立即关闭并退出。当虚拟机由于用户注销或系统关闭而终止时，底层操作系统可能只允许关闭和退出的固定时间量。因此，不建议尝试任何用户交互或在关闭挂钩中执行长时间运行的计算。
 * 与在任何其他线程中一样，通过调用线程的ThreadGroup对象的uncaughtException方法，在关闭挂钩中处理未捕获的异常。此方法的默认实现将异常的堆栈跟踪打印到System.err并终止线程；它不会导致虚拟机退出或停止。
 * 在极少数情况下，虚拟机可能会中止，即停止运行而没有完全关闭。当虚拟机在外部终止时会发生这种情况，例如在 Unix 上使用SIGKILL信号或在 Microsoft Windows 上使用TerminateProcess调用。如果本地方法出错，例如破坏内部数据结构或尝试访问不存在的内存，虚拟机也可能中止。如果虚拟机中止，则无法保证是否会运行任何关闭挂钩。
 *
 *
 * 参数：
 * hook - 一个已初始化但未启动的Thread对象
 * 抛出：
 * IllegalArgumentException – 如果指定的钩子已经注册，或者可以确定钩子已经在运行或已经运行
 * IllegalStateException – 如果虚拟机已经在关闭过程中
 * SecurityException – 如果存在安全管理器并且它拒绝RuntimePermission ("shutdownHooks")
 * 自从：
 * 1.3
 * 也可以看看：
 * removeShutdownHook , halt(int) , exit(int)
 */
@Component
public class CustomShutdownHook {

    private static final Logger log = LoggerFactory.getLogger(CustomShutdownHook.class);

    @PostConstruct
    public void testAddShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                try {
                    log.info("我这个钩子运行结束...");
                } catch (Exception ignored) {

                }
            }
        });
        log.info(LogConstant.SPRING_LOG, "注册自定义钩子 完成");
    }
}
